/*
 *  Class name: XStreamXmlProvider.java
 *  Version: 1.0
 *  Date: 16.12.2013
 */
package cz.muni.fi.pa165.soccergamesarchive.common.providers;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.XStreamException;
import com.thoughtworks.xstream.io.xml.CompactWriter;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.PlayerDTO;
import cz.muni.fi.pa165.soccergamesarchive.businesslayer.dtos.TeamDTO;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;

/**
 *
 * @author Michal Ďuriš
 */
@Consumes(value = {MediaType.APPLICATION_XML, MediaType.TEXT_XML,
                   MediaType.WILDCARD})
@Produces(value = {MediaType.APPLICATION_XML, MediaType.TEXT_XML,
                   MediaType.WILDCARD})
@Provider
public class XStreamXmlProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object>{

    private static final String DEFAULT_ENCODING = "utf-8";

//  Todo: Rethink this...
    private static final Class[] MAPPED_CLASSES = {TeamDTO.class,
                                                   PlayerDTO.class};

    private XStream xStream;

    public XStreamXmlProvider() {
    }

    private void createXStream() {
        xStream = new XStream();
        xStream.autodetectAnnotations(true);
    }

    private String getCharsetAsString(MediaType mediaType) {
        if (mediaType == null) {
            return DEFAULT_ENCODING;
        }

        String charset = mediaType.getParameters().get("charset");

        return charset == null ? DEFAULT_ENCODING : charset;
    }

    @Override
    public boolean isReadable(
            Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public Object readFrom(Class<Object> type, Type genericType,
                           Annotation[] annotations, MediaType mediaType,
                           MultivaluedMap<String, String> httpHeaders,
                           InputStream entityStream) throws IOException,
                                                            WebApplicationException {

        createXStream();

        xStream.processAnnotations(MAPPED_CLASSES);

        Object responseObject = null;

        try {
            if (entityStream != null && entityStream.available() > 0) {
                responseObject = xStream.fromXML(new InputStreamReader(
                        entityStream,
                        getCharsetAsString(mediaType)));
            }

        } catch (UnsupportedEncodingException | XStreamException ex) {
            //Todo: Logger
            System.err.println("Deserializer phase exception " + ex);
        }

        return responseObject;
    }

    @Override
    public boolean isWriteable(
            Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return true;
    }

    @Override
    public long getSize(Object t,
                        Class<?> type, Type genericType,
                        Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public void writeTo(Object t,
                        Class<?> type, Type genericType,
                        Annotation[] annotations, MediaType mediaType,
                        MultivaluedMap<String, Object> httpHeaders,
                        OutputStream entityStream) throws IOException,
                                                          WebApplicationException {
        createXStream();

        try {
            xStream.marshal(t, new CompactWriter(
                    new OutputStreamWriter(entityStream, getCharsetAsString(
                                    mediaType))));
        } catch (UnsupportedEncodingException | XStreamException ex) {
            //Todo: Logger
            System.err.println("Serializer phase exception " + ex);
        }
    }

}
